package top.milkbox.sys.modular.relationship.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.milkbox.common.bo.EntityColumnExistence;
import top.milkbox.common.exceprion.CommonServiceException;
import top.milkbox.sys.modular.menu.entity.SysMenuEntity;
import top.milkbox.sys.modular.menu.service.SysMenuService;
import top.milkbox.sys.modular.relationship.bo.SysRelationshipObjectAuthTargetBo;
import top.milkbox.sys.modular.relationship.bo.SysRelationshipTargetAuthObjectBo;
import top.milkbox.sys.modular.relationship.entity.SysRelationshipEntity;
import top.milkbox.sys.modular.relationship.enums.SysRelationshipTypeEnum;
import top.milkbox.sys.modular.relationship.mapStruct.SysRelationshipMapStruct;
import top.milkbox.sys.modular.relationship.mapper.SysRelationshipMapper;
import top.milkbox.sys.modular.relationship.param.SysRelationshipAddParam;
import top.milkbox.sys.modular.relationship.param.SysRelationshipEditParam;
import top.milkbox.sys.modular.relationship.param.SysRelationshipIdParam;
import top.milkbox.sys.modular.relationship.service.SysRelationshipService;
import top.milkbox.sys.modular.relationship.vo.SysRelationshipVo;
import top.milkbox.sys.modular.role.entity.SysRoleEntity;
import top.milkbox.sys.modular.role.param.SysRoleAuthorizationMenuParam;
import top.milkbox.sys.modular.role.param.SysRoleAuthorizationUserParam;
import top.milkbox.sys.modular.role.service.SysRoleService;
import top.milkbox.sys.modular.user.entity.SysUserEntity;
import top.milkbox.sys.modular.user.param.SysUserAuthorizationMenuParam;
import top.milkbox.sys.modular.user.param.SysUserAuthorizationRoleParam;
import top.milkbox.sys.modular.user.service.SysUserService;

import java.util.*;

/**
 * 系统_关系表_用户角色组织菜单权限综合关系表（sys_relationship）服务层实现类
 *
 * @author milkbox
 * @date 2024-1-23
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysRelationshipServiceImpl
        extends ServiceImpl<SysRelationshipMapper, SysRelationshipEntity>
        implements SysRelationshipService {

    private SysRelationshipMapper sysRelationshipMapper;
    private SysRelationshipMapStruct sysRelationshipMapStruct;

    private SysUserService sysUserService;
    private SysRoleService sysRoleService;
    private SysMenuService sysMenuService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysRelationshipAddParam addParam) {
        SysRelationshipEntity entity = sysRelationshipMapStruct.addParamToEntity(addParam);
        super.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<SysRelationshipIdParam> paramList) {
        super.removeByIds(paramList.stream().map(SysRelationshipIdParam::getId).toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysRelationshipEditParam editParam) {
        findEntity(editParam.getId());
        SysRelationshipEntity entity = sysRelationshipMapStruct.editParamToEntity(editParam);
        super.updateById(entity);
    }

    @Override
    public SysRelationshipVo detail(SysRelationshipIdParam idParam) {
        SysRelationshipEntity entity = findEntity(idParam.getId());
        SysRelationshipVo vo = sysRelationshipMapStruct.entityToVo(entity);
        // 此处进行数据翻译操作，，根据不同的业务逻辑将entity对象转为vo对象......

        return vo;
    }

    @Override
    public SysRelationshipEntity findEntity(Integer entityId) {
        SysRelationshipEntity entity = super.getById(entityId);
        if (ObjectUtil.isEmpty(entity)) {
            throw new CommonServiceException("实体未找到（{}）", entityId);
        }
        return entity;
    }

    @Override
    public List<Integer> findTargetIdListByObjectId(Integer objectId, SysRelationshipTypeEnum type) {
        LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysRelationshipEntity::getObjectId, objectId)
                // 在类型不为空的情况下，添加此条件
                .eq(ObjectUtil.isNotEmpty(type), SysRelationshipEntity::getCategory, type);
        List<Integer> targetIdList = super.list(queryWrapper).stream().map(SysRelationshipEntity::getTargetId).toList();
        return targetIdList;
    }

    @Override
    public List<Integer> findObjectIdListByTargetId(Integer targetId, SysRelationshipTypeEnum type) {
        LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysRelationshipEntity::getTargetId, targetId)
                // 在类型不为空的情况下，添加此条件
                .eq(ObjectUtil.isNotEmpty(type), SysRelationshipEntity::getCategory, type);
        List<Integer> objectIdList = super.list(queryWrapper).stream().map(SysRelationshipEntity::getObjectId).toList();
        return objectIdList;
    }

    @Override
    public void deleteByObjectAndType(List<Integer> deleteObjectList, SysRelationshipTypeEnum type) {
        if (ObjectUtil.isEmpty(deleteObjectList)) {
            return;
        }
        LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysRelationshipEntity::getObjectId, deleteObjectList)
                // 在类型不为空的情况下，添加此条件
                .eq(ObjectUtil.isNotEmpty(type), SysRelationshipEntity::getCategory, type);
        super.remove(queryWrapper);
    }

    @Override
    public void deleteByTargetAndType(List<Integer> deleteTargetList, SysRelationshipTypeEnum type) {
        if (ObjectUtil.isEmpty(deleteTargetList)) {
            return;
        }
        LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysRelationshipEntity::getTargetId, deleteTargetList)
                // 在类型不为空的情况下，添加此条件
                .eq(ObjectUtil.isNotEmpty(type), SysRelationshipEntity::getCategory, type);
        super.remove(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> objectAuthTarget(
            SysRelationshipObjectAuthTargetBo objectAuthTargetBo,
            EntityColumnExistence<Integer> entityColumnExistence) {

        // 分别处理重新授权与追加授权
        if (objectAuthTargetBo.getIsReauthorization() != null && objectAuthTargetBo.getIsReauthorization()) {
            // 重新授权

            // 构造实体集合
            List<SysRelationshipEntity> relationshipEntityList = entityColumnExistence.getExistColumnList().stream()
                    .map(targetId -> new SysRelationshipEntity(
                            objectAuthTargetBo.getObjectId(), targetId, objectAuthTargetBo.getCategory()))
                    .toList();
            // 删除此objectId原来的授权信息
            deleteByObjectAndType(Collections.singletonList(objectAuthTargetBo.getObjectId()),
                    objectAuthTargetBo.getCategory());
            // 保存实体信息
            super.saveBatch(relationshipEntityList);
        } else {
            // 追加授权

            // 判断targetIdList是否为空，如果为空则没必要进行授权操作
            if (ObjectUtil.isEmpty(entityColumnExistence.getExistColumnList())) {
                throw new CommonServiceException("授权的集合{}中无可用的对象，授权停止",
                        objectAuthTargetBo.getTargetIdList());
            }

            // 查询此objectId授权的信息
            LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysRelationshipEntity::getObjectId, objectAuthTargetBo.getObjectId())
                    .eq(SysRelationshipEntity::getCategory, objectAuthTargetBo.getCategory());
            List<SysRelationshipEntity> roleRelationshipList = super.list(queryWrapper);

            // 去掉已经授权的targetId，得到需要追加的菜单targetId
            List<Integer> additionAuthorizationMenuIdList = new ArrayList<>(entityColumnExistence.getExistColumnList());
            additionAuthorizationMenuIdList.removeAll(roleRelationshipList.stream()
                    .map(SysRelationshipEntity::getTargetId).toList());

            // 构造实体集合
            List<SysRelationshipEntity> entityList = additionAuthorizationMenuIdList.stream()
                    .map(targetId -> new SysRelationshipEntity(
                            objectAuthTargetBo.getObjectId(), targetId, objectAuthTargetBo.getCategory()))
                    .toList();
            super.saveBatch(entityList);
        }
        return entityColumnExistence;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> targetAuthObject(
            SysRelationshipTargetAuthObjectBo targetAuthObjectBo,
            EntityColumnExistence<Integer> entityColumnExistence) {

        // 分别处理重新授权与追加授权
        if (targetAuthObjectBo.getIsReauthorization() != null && targetAuthObjectBo.getIsReauthorization()) {
            // 重新授权

            // 构造实体集合
            List<SysRelationshipEntity> relationshipEntityList = entityColumnExistence.getExistColumnList().stream()
                    .map(objectId -> new SysRelationshipEntity(
                            objectId, targetAuthObjectBo.getTargetId(), targetAuthObjectBo.getCategory()))
                    .toList();
            // 删除此targetId原来的授权信息
            deleteByTargetAndType(Collections.singletonList(targetAuthObjectBo.getTargetId()),
                    targetAuthObjectBo.getCategory());
            // 保存实体信息
            super.saveBatch(relationshipEntityList);
        } else {
            // 追加授权

            // 判断objectIdList是否为空，如果为空则没必要进行授权操作
            if (ObjectUtil.isEmpty(entityColumnExistence.getExistColumnList())) {
                throw new CommonServiceException("授权的集合{}中无可用的对象，授权停止",
                        targetAuthObjectBo.getObjectIdList());
            }

            // 查询此targetId已经授权的对象信息
            LambdaQueryWrapper<SysRelationshipEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysRelationshipEntity::getTargetId, targetAuthObjectBo.getTargetId())
                    .eq(SysRelationshipEntity::getCategory, targetAuthObjectBo.getCategory());
            List<SysRelationshipEntity> targetRelationshipList = super.list(queryWrapper);

            // 去掉已经授权的对象id，得到需要追加的对象id列表
            List<Integer> additionAuthorizationObjectList = new ArrayList<>(entityColumnExistence.getExistColumnList());
            additionAuthorizationObjectList.removeAll(targetRelationshipList.stream()
                    .map(SysRelationshipEntity::getObjectId).toList());

            // 构造需要追加的实体集合
            List<SysRelationshipEntity> entityList = additionAuthorizationObjectList.stream()
                    .map(objectId -> new SysRelationshipEntity(
                            objectId, targetAuthObjectBo.getTargetId(), targetAuthObjectBo.getCategory()))
                    .toList();
            super.saveBatch(entityList);
        }
        return entityColumnExistence;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> roleIdAuthUserIdList(SysRoleAuthorizationUserParam param) {
        // 检查角色是否存在
        sysRoleService.findEntity(param.getRoleId());

        // 创建bo对象（实际的作用就是额外添加了category属性）
        SysRelationshipTargetAuthObjectBo targetAuthObjectBo = new SysRelationshipTargetAuthObjectBo(
                param.getUserIdList(),
                param.getRoleId(),
                param.getIsReauthorization(),
                SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_ROLE
        );

        // 列存在性对象，查询用户id集合中存在的id和不存在的id
        EntityColumnExistence<Integer> columnExistence =
                sysUserService.filterDoesNotExistColumn(SysUserEntity::getId, param.getUserIdList());
        // 调用objectId授权targetIdList方法
        return targetAuthObject(targetAuthObjectBo, columnExistence);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> roleIdAuthMenuIdList(SysRoleAuthorizationMenuParam param) {
        // 检查角色是否存在
        sysRoleService.findEntity(param.getRoleId());

        // 创建bo对象（实际的作用就是额外添加了category属性）
        SysRelationshipObjectAuthTargetBo objectAuthTargetBo = new SysRelationshipObjectAuthTargetBo(
                param.getRoleId(),
                param.getMenuIdList(),
                param.getIsReauthorization(),
                SysRelationshipTypeEnum.SYS_ROLE_RELATE_SYS_MENU);

        // 列存在性对象，查询菜单id集合中存在的id和不存在的id
        EntityColumnExistence<Integer> columnExistence =
                sysMenuService.filterDoesNotExistColumn(SysMenuEntity::getId, param.getMenuIdList());
        // 调用objectId授权targetIdList方法
        return objectAuthTarget(objectAuthTargetBo, columnExistence);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> userIdAuthMenuIdList(SysUserAuthorizationMenuParam param) {
        // 检查用户是否存在
        sysUserService.findEntity(param.getUserId());

        // 创建bo对象（实际的作用就是额外添加了category属性）
        SysRelationshipObjectAuthTargetBo objectAuthTargetBo = new SysRelationshipObjectAuthTargetBo(
                param.getUserId(),
                param.getMenuIdList(),
                param.getIsReauthorization(),
                SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_MENU);

        // 列存在性对象，查询菜单id集合中存在的id和不存在的id
        EntityColumnExistence<Integer> columnExistence =
                sysMenuService.filterDoesNotExistColumn(SysMenuEntity::getId, param.getMenuIdList());
        // 调用objectId授权targetIdList方法
        return objectAuthTarget(objectAuthTargetBo, columnExistence);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EntityColumnExistence<Integer> userIdAuthRoleIdList(SysUserAuthorizationRoleParam param) {
        // 检查用户是否存在
        sysUserService.findEntity(param.getUserId());

        // 创建bo对象（实际的作用就是额外添加了category属性）
        SysRelationshipObjectAuthTargetBo objectAuthTargetBo = new SysRelationshipObjectAuthTargetBo(
                param.getUserId(),
                param.getRoleIdList(),
                param.getIsReauthorization(),
                SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_ROLE);

        // 列存在性对象，查询角色id集合中存在的id和不存在的id
        EntityColumnExistence<Integer> columnExistence =
                sysRoleService.filterDoesNotExistColumn(SysRoleEntity::getId, param.getRoleIdList());
        // 调用objectId授权targetIdList方法
        return objectAuthTarget(objectAuthTargetBo, columnExistence);
    }

    @Override
    public List<Integer> findAllMenuIdListByUserId(Integer userId) {
        // 查询用户所属的角色拥有权限的菜单id集合
        List<Integer> roleIdList = findTargetIdListByObjectId(userId, SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_ROLE);
        List<Integer> roleMenuList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(roleIdList)) {
            roleMenuList = list(new LambdaUpdateWrapper<SysRelationshipEntity>()
                    .in(SysRelationshipEntity::getObjectId, roleIdList)
                    .eq(SysRelationshipEntity::getCategory, SysRelationshipTypeEnum.SYS_ROLE_RELATE_SYS_MENU)
            ).stream().map(SysRelationshipEntity::getTargetId).toList();
        }

        // 查询用户独有权限的菜单id集合
        List<Integer> userMenuIdList = findTargetIdListByObjectId(userId, SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_MENU);

        if (ObjectUtil.isAllEmpty(roleMenuList, userMenuIdList)) {
            // 如果没有数据，则返回空
            return new ArrayList<>();
        }

        // 合并两个集合，使用set去重
        Set<Integer> menuIdSet = new HashSet<>();
        menuIdSet.addAll(roleMenuList);
        menuIdSet.addAll(userMenuIdList);

        return new ArrayList<>(menuIdSet);
    }

    @Override
    public List<Integer> findAllPermissionIdListByUserId(Integer userId) {
        // 查询用户所属的角色关联的权限id集合
        List<Integer> roleIdList = findTargetIdListByObjectId(userId, SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_ROLE);
        List<Integer> rolePermissionList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(roleIdList)) {
            rolePermissionList = list(new LambdaUpdateWrapper<SysRelationshipEntity>()
                    .in(SysRelationshipEntity::getObjectId, roleIdList)
                    .eq(SysRelationshipEntity::getCategory, SysRelationshipTypeEnum.SYS_ROLE_RELATE_SYS_PERMISSION)
            ).stream().map(SysRelationshipEntity::getTargetId).toList();
        }

        // 查询用户独有权限的权限id集合
        List<Integer> userPermissionIdList = findTargetIdListByObjectId(userId, SysRelationshipTypeEnum.SYS_USER_RELATE_SYS_PERMISSION);

        if (ObjectUtil.isAllEmpty(rolePermissionList, userPermissionIdList)) {
            // 如果没有数据，则返回空
            return new ArrayList<>();
        }

        // 合并两个集合，使用set去重
        Set<Integer> menuIdSet = new HashSet<>();
        menuIdSet.addAll(rolePermissionList);
        menuIdSet.addAll(userPermissionIdList);

        return new ArrayList<>(menuIdSet);
    }

}
